part of 'screen_adapter.dart';

class ScreenAdapterInit extends StatefulWidget {
  const ScreenAdapterInit({
    super.key,
    this.designSize,
    required this.builder,
    this.responsiveWidgets,
  });

  final Widget Function(BuildContext context) builder;

  final Size? designSize;
  final Iterable<String>? responsiveWidgets;

  @override
  State<ScreenAdapterInit> createState() => _ScreenAdapterInitState();
}

class _ScreenAdapterInitState extends State<ScreenAdapterInit>
    with WidgetsBindingObserver {
  final _canMarkedToBuild = HashSet<String>();
  final _binding = WidgetsBinding.instance;
  final _screenSizeComplete = Completer<void>();

  MediaQueryData? _mediaQueryData;

  void _init() {
    if (_mediaQueryData != null) {
      return;
    }

    _validateSize().then((_) {
      var data = MediaQuery.of(context);
      showDialog(
        context: context,
        builder: (context) {
          return Container(
            color: Colors.red,
            child: Column(
              children: [
                Text(data.toString()),
              ],
            ),
          );
        },
      );
      if (!data.size.isEmpty) {
        _mediaQueryData = data;
        ScreenAdapter.init(designSize: widget.designSize, context: context);
        _screenSizeComplete.complete();
      }
    });
  }

  Future<void> _validateSize() async {
    return ScreenAdapter.ensureScreenSize();
  }

  void _markNeedsBuildIfAllowed(Element el) {
    final widgetName = el.widget.runtimeType.toString();
    final allowed =
        _canMarkedToBuild.contains(widgetName) || !(widgetName.startsWith('_'));

    if (allowed) el.markNeedsBuild();
  }

  void _updateTree(Element el) {
    _markNeedsBuildIfAllowed(el);
    el.visitChildren(_updateTree);
  }

  void _revalidate() {
    final oldData = _mediaQueryData;
    final newData = _newData();

    if (newData == null) return;

    if (oldData == null) {
      setState(() {
        _mediaQueryData = newData;
        _updateTree(context as Element);
      });
    }
  }

  MediaQueryData? _newData() {
    MediaQueryData? mq = MediaQuery.maybeOf(context);
    mq ??= MediaQueryData.fromView(View.of(context));

    return mq;
  }

  @override
  void initState() {
    if (widget.responsiveWidgets != null) {
      _canMarkedToBuild.addAll(widget.responsiveWidgets!);
    }
    _init();
    super.initState();
    _binding.addObserver(this);
  }

  @override
  void didUpdateWidget(covariant ScreenAdapterInit oldWidget) {
    _init();
    super.didUpdateWidget(oldWidget);
  }

  @override
  void didChangeDependencies() {
    _revalidate();
    super.didChangeDependencies();
  }

  @override
  void didChangeMetrics() {
    _revalidate();
    super.didChangeMetrics();
  }

  @override
  void dispose() {
    _binding.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _screenSizeComplete.future,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return widget.builder.call(context);
        }

        return const SizedBox.shrink();
      },
    );
  }
}
